package cn.com.dcsgo.exception.handler;

import cn.com.dcsgo.constant.BusinessEnum;
import cn.com.dcsgo.exception.BusinessException;
import cn.com.dcsgo.model.Result;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.ConstraintViolation;
import org.springframework.security.access.AccessDeniedException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 *
 * @author Dcsgo
 * @since 2025/9/19 17:17
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    public Result<String> businessExceptionHandler(BusinessException e) {
        return Result.fail(BusinessEnum.OPERATION_FAIL.getCode(), e.getMessage());
    }

    /*
     * 参数校验异常处理
     */
    @ExceptionHandler(BindException.class)
    public Result<String> bindExceptionHandler(BindException e) {
        List<ObjectError> allErrors = e.getAllErrors();
        StringBuilder sb = new StringBuilder();
        allErrors.forEach(objectError -> {
            String message = objectError.getDefaultMessage();
            sb.append(message).append("\n");
        });
        // 删除最后一个换行符
        String realMsg = sb.substring(0, sb.length() - 1);
        return Result.fail(BusinessEnum.PARAMS_ERROR_FAIL.getCode(), realMsg);
    }

    /*
     * 参数校验异常处理
     * @Validated 标在 Controller 类上并在接口参数上直接使用参数校验注解时会抛出这个异常
     * 参考资料：https://juejin.cn/post/7087100869363122189
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<String> constraintViolationExceptionHandler(ConstraintViolationException e) {
        // 只拿友好提示，不要前缀；多条提示用“，”隔开
        String msg = e.getConstraintViolations()
                .stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining("，"));
        return Result.fail(BusinessEnum.PARAMS_ERROR_FAIL.getCode(), msg);
    }

    /*
     * 断言异常处理
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public Result<String> illegalArgumentExceptionHandler(IllegalArgumentException e) {
        return Result.fail(BusinessEnum.PARAMS_ERROR_FAIL.getCode(), e.getMessage());
    }

    /**
     * 权限不足异常处理 不处理交由ResourceServerConfig中的accessDeniedHandler处理
     * 注意：此方法会优先于ResourceServerConfig中的accessDeniedHandler处理权限异常
     * Spring Security的异常处理优先级：@RestControllerAdvice > 过滤器级别的异常处理器
     */
    @ExceptionHandler(AccessDeniedException.class)
    public Result<String> accessDeniedExceptionHandler(AccessDeniedException e) {
        throw e;
    }

    @ExceptionHandler(Throwable.class)
    public Result<String> throwableHandler(Throwable e) {
        log.error("===============系统异常===============", e);
        return Result.fail(BusinessEnum.SERVER_INNER_ERROR);
    }
}
